/**
 * 自定义指令
 */
import type { App, DirectiveBinding } from "vue";

// 防抖指令
const debounce = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    let timer: ReturnType<typeof setTimeout> | null = null;
    const delay = binding.arg ? parseInt(binding.arg) : 300;

    el.addEventListener("click", () => {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => {
        binding.value();
      }, delay);
    });
  },
};

// 节流指令
const throttle = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    let timer: ReturnType<typeof setTimeout> | null = null;
    const delay = binding.arg ? parseInt(binding.arg) : 300;

    el.addEventListener("click", () => {
      if (!timer) {
        binding.value();
        timer = setTimeout(() => {
          timer = null;
        }, delay);
      }
    });
  },
};

// 复制指令
const copy = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    el.addEventListener("click", async () => {
      const text = binding.value || el.textContent || "";

      try {
        if (navigator.clipboard && window.isSecureContext) {
          await navigator.clipboard.writeText(text);
        } else {
          // 降级方案
          const textArea = document.createElement("textarea");
          textArea.value = text;
          textArea.style.position = "fixed";
          textArea.style.left = "-999999px";
          textArea.style.top = "-999999px";
          document.body.appendChild(textArea);
          textArea.focus();
          textArea.select();
          document.execCommand("copy");
          document.body.removeChild(textArea);
        }

        // 显示成功提示
        const event = new CustomEvent("copy-success", { detail: { text } });
        el.dispatchEvent(event);
      } catch (error) {
        // 显示失败提示
        const event = new CustomEvent("copy-error", { detail: { error } });
        el.dispatchEvent(event);
      }
    });
  },
};

// 长按指令
const longpress = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    let timer: ReturnType<typeof setTimeout> | null = null;
    const duration = binding.arg ? parseInt(binding.arg) : 500;

    const start = () => {
      timer = setTimeout(() => {
        binding.value();
      }, duration);
    };

    const cancel = () => {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
    };

    el.addEventListener("mousedown", start);
    el.addEventListener("mouseup", cancel);
    el.addEventListener("mouseleave", cancel);
    el.addEventListener("touchstart", start);
    el.addEventListener("touchend", cancel);
    el.addEventListener("touchcancel", cancel);
  },
};

// 拖拽指令
const draggable = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    let isDragging = false;
    let startX = 0;
    let startY = 0;
    let initialX = 0;
    let initialY = 0;

    const onMouseDown = (e: MouseEvent) => {
      isDragging = true;
      startX = e.clientX;
      startY = e.clientY;

      const rect = el.getBoundingClientRect();
      initialX = rect.left;
      initialY = rect.top;

      el.style.cursor = "grabbing";
      el.style.userSelect = "none";

      document.addEventListener("mousemove", onMouseMove);
      document.addEventListener("mouseup", onMouseUp);
    };

    const onMouseMove = (e: MouseEvent) => {
      if (!isDragging) return;

      const deltaX = e.clientX - startX;
      const deltaY = e.clientY - startY;

      el.style.position = "fixed";
      el.style.left = `${initialX + deltaX}px`;
      el.style.top = `${initialY + deltaY}px`;
      el.style.zIndex = "9999";
    };

    const onMouseUp = () => {
      isDragging = false;
      el.style.cursor = "grab";
      el.style.userSelect = "auto";

      document.removeEventListener("mousemove", onMouseMove);
      document.removeEventListener("mouseup", onMouseUp);

      if (binding.value && typeof binding.value === "function") {
        binding.value({
          x: parseInt(el.style.left),
          y: parseInt(el.style.top),
        });
      }
    };

    el.style.cursor = "grab";
    el.addEventListener("mousedown", onMouseDown);
  },
};

// 懒加载指令
const lazy = {
  mounted(el: HTMLImageElement, binding: DirectiveBinding) {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          const img = entry.target as HTMLImageElement;
          img.src = binding.value;
          img.classList.remove("lazy-loading");
          img.classList.add("lazy-loaded");
          observer.unobserve(img);
        }
      });
    });

    el.classList.add("lazy-loading");
    observer.observe(el);
  },
};

// 权限指令
const permission = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const { value } = binding;
    const permissions = JSON.parse(
      localStorage.getItem("user_permissions") || "[]",
    );

    if (!permissions.includes(value)) {
      el.style.display = "none";
    }
  },

  updated(el: HTMLElement, binding: DirectiveBinding) {
    const { value } = binding;
    const permissions = JSON.parse(
      localStorage.getItem("user_permissions") || "[]",
    );

    if (!permissions.includes(value)) {
      el.style.display = "none";
    } else {
      el.style.display = "";
    }
  },
};

// 水印指令
const watermark = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const { value } = binding;
    const text = value.text || "Watermark";
    const fontSize = value.fontSize || "16px";
    const color = value.color || "rgba(0, 0, 0, 0.1)";
    const rotate = value.rotate || -20;

    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d")!;

    canvas.width = 200;
    canvas.height = 100;

    ctx.font = fontSize + " Arial";
    ctx.fillStyle = color;
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.rotate((rotate * Math.PI) / 180);
    ctx.fillText(text, canvas.width / 2, canvas.height / 2);

    const dataURL = canvas.toDataURL();

    el.style.position = "relative";
    el.style.backgroundImage = `url(${dataURL})`;
    el.style.backgroundRepeat = "repeat";
  },
};

// 无限滚动指令
const infiniteScroll = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const callback = binding.value;
    const options = {
      threshold: 0.1,
      rootMargin: "0px 0px 100px 0px",
    };

    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          callback();
        }
      });
    }, options);

    // 创建一个底部触发元素
    const trigger = document.createElement("div");
    trigger.style.height = "1px";
    trigger.style.width = "100%";
    el.appendChild(trigger);

    observer.observe(trigger);

    // 保存 observer 以便清理
    (el as any)._infiniteScrollObserver = observer;
    (el as any)._infiniteScrollTrigger = trigger;
  },

  unmounted(el: HTMLElement) {
    const observer = (el as any)._infiniteScrollObserver;
    const trigger = (el as any)._infiniteScrollTrigger;

    if (observer) {
      observer.disconnect();
    }

    if (trigger && trigger.parentNode) {
      trigger.parentNode.removeChild(trigger);
    }
  },
};

// 点击外部指令
const clickOutside = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const callback = binding.value;

    const handler = (e: Event) => {
      if (!el.contains(e.target as Node)) {
        callback();
      }
    };

    document.addEventListener("click", handler);
    (el as any)._clickOutsideHandler = handler;
  },

  unmounted(el: HTMLElement) {
    const handler = (el as any)._clickOutsideHandler;
    if (handler) {
      document.removeEventListener("click", handler);
    }
  },
};

// 自动聚焦指令
const focus = {
  mounted(el: HTMLElement) {
    el.focus();
  },
};

// 数字动画指令
const numberAnimation = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const endValue = binding.value;
    const duration = binding.arg ? parseInt(binding.arg) : 1000;

    const startValue = 0;
    const startTime = Date.now();

    const animate = () => {
      const now = Date.now();
      const progress = Math.min((now - startTime) / duration, 1);

      const currentValue = Math.floor(
        startValue + (endValue - startValue) * progress,
      );
      el.textContent = currentValue.toString();

      if (progress < 1) {
        requestAnimationFrame(animate);
      }
    };

    animate();
  },
};

// 导出所有指令
const directives = {
  debounce,
  throttle,
  copy,
  longpress,
  draggable,
  lazy,
  permission,
  watermark,
  infiniteScroll,
  clickOutside,
  focus,
  numberAnimation,
};

// 安装指令的函数
export function setupDirectives(app: App) {
  Object.keys(directives).forEach((key) => {
    app.directive(key, directives[key as keyof typeof directives]);
  });
}

export default directives;
